#include <QUdpSocket>
#include <QPushButton>
#include <QHostAddress>
#include <QVBoxLayout>
#include <QHostAddress>
#include <QCloseEvent>
#include <QFile>

#include <termios.h>
#include <fcntl.h>
#include <iostream>

#include "linkqualityecho.h"

using namespace std;

const char COM[20] = "/dev/ttyUSB0";
const char remoteAddr[100] = "192.168.1.100";
const int port = 11111;
const int receive_port = 11112;

LinkQualityEcho::LinkQualityEcho(QWidget *parent)
    :QDialog(parent)
{
    loadGUI();

    thread = new updateGPS;
    thread->start();

    server = new UDPServer;
    server->start();

    s = 0;

    connect(server, SIGNAL(receiveCMD(QByteArray*)), this, SLOT(sendReply(QByteArray*)));
    connect(thread, SIGNAL(updateData(QString)), this, SLOT(updateGPSData(QString)));
}

void LinkQualityEcho::loadGUI()
{
    setFixedSize(320, 240);

    startButton = new QPushButton(tr("Start"));
    closeButton = new QPushButton(tr("Close"));

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(startButton);
    mainLayout->addWidget(closeButton);
    setLayout(mainLayout);

    connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
}

void LinkQualityEcho::updateGPSData(QString gps)
{
    this->gps = gps;
    //cout<<"update "<<endl;
}

void LinkQualityEcho::closeEvent(QCloseEvent *event)
{
    if(thread->isRunning())
    {
        thread->stop();
        thread->wait();

        thread->deleteLater();
    }

    if(server->isRunning())
    {
        server->quit();
        server->wait();
        server->deleteLater();
    }
    event->accept();
}

void LinkQualityEcho::sendReply(QByteArray *data)
{
    QUdpSocket sendSocket;
    QByteArray datagram;
    QDataStream *out = new QDataStream(&datagram, QIODevice::WriteOnly);
    *out<<quint16(2)<<this->gps;
    sendSocket.writeDatagram(datagram, QHostAddress(remoteAddr), port);
    out = new QDataStream(data, QIODevice::ReadWrite);
    out->device()->seek(0);
    *out<<quint16(3);
    sendSocket.writeDatagram(*data, QHostAddress(remoteAddr), port);
    //sendSocket.flush();

    //cout<<"send data"<<endl;
}

void updateGPS::stop()
{
    stopped = true;
}

int updateGPS::openPort()
{
    int fd;
    fd = ::open(COM, O_RDWR | O_NOCTTY | O_NDELAY);
    cout<<"open com "<<COM<<endl;
    if(fd == -1)
    {
        cout<<"open_port: Unable to open "<<COM<<endl;
        exit(1);
    }
    else
    {
        fcntl(fd, F_SETFL, 0);
    }

    return fd;
}

void updateGPS::run()
{
    struct termios options;
    int fd;

    fd = this->openPort();
    /*
     *Get the current options for the port...
     */
    tcgetattr(fd, &options);

    /*
     *Set the baud rates to 19200...
     */
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);

    /*
     *Set Parity check
     */
    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    /*
     *Set hardware flow control
     */
    //options.c_cflag &= ~CNEW_RTSCTS;

    /*
     *Enable the receiver and set local mode ...
     */
    options.c_cflag |= (CLOCAL | CREAD);
    /*
     *Set the new options for the port...
     */
    tcsetattr(fd, TCSANOW, &options);

    fcntl(fd, F_SETFL, 0);

    char buff[1024];

    QString str;
    QTextStream stream(&str);
    QString line;
    line.clear();

    while(stopped == false)
    {
        int readn = 0;
        memset(buff, 0, sizeof(buff));
        readn = ::read(fd, buff, sizeof(buff));
        int i = 0;
        while(buff[i] == 0) i++;
        stream<<QByteArray(buff + i, readn);

        line.clear();
        while((line = stream.readLine()) != NULL)
        {
            char *charLine = line.toAscii().data();

            if(strlen(charLine) <= 4 || charLine[0] != '$' || charLine[line.length() - 3] != '*')
            {
                stream<<line;
                break;
            }
            if(line.indexOf(QString("GPRMC")) != -1)
            {
                if(strlen(charLine) <= 4)
                    break;

                //sendSocket.writeDatagram(line.toAscii().data(), line.size(), QHostAddress(remoteAddr), port);
                emit updateData(line);
                //cout<<line.toAscii().data()<<endl;
            }
        }
    }//end while(1)
    cout<<"stopped"<<endl;
    ::close(fd);
}

UDPServer::UDPServer()
{
    receiveSocket = new QUdpSocket;
    receiveSocket->bind(receive_port);

    connect(receiveSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
}

void UDPServer::processPendingDatagrams()
{
    cout<<"processPendingDatagrams"<<endl;
    QByteArray datagram;

    datagram.resize(receiveSocket->pendingDatagramSize());
    receiveSocket->readDatagram(datagram.data(), datagram.size());

    QDataStream in(&datagram, QIODevice::ReadOnly);
    qint16 type;
    in>>type;
    if(type == qint16(1))
    {
        cout<<datagram.size()<<endl;
        emit receiveCMD(&datagram);
    }
}

